<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <title>数据管理系统</title>
  <style>
    .app-container {
      padding: 20px;
    }
    .price-up {
      color: #f56c6c;
      font-weight: bold;
    }
    .price-down {
      color: #67c23a;
      font-weight: bold;
    }
    .sort-container {
      display: flex;
      align-items: center;
      padding: 0 10px;
    }
    .stats-result {
      margin-top: 20px;
      font-size: 16px;
      color: #333;
      padding: 10px;
      border-radius: 4px;
      background-color: #f5f7fa;
    }
  </style>
</head>
<body>
<div id="app" v-cloak>
  <div class="app-container">
    <!-- 顶部菜单 -->
    <el-menu
      :default-active="activeIndex"
      class="el-menu-demo"
      mode="horizontal"
      @select="handleSelect"
      background-color="#545c64"
      text-color="#fff"
      active-text-color="#ffd04b"
    >
      <el-menu-item index="1">数据展示</el-menu-item>
      <el-menu-item index="2">美股分析</el-menu-item>
      <el-menu-item index="3">沪深京股分析</el-menu-item>
      <el-menu-item index="4">数据爬取</el-menu-item>
      <el-menu-item index="5">处理中心</el-menu-item>

      <!-- 排序组件 -->
      <el-menu-item index="sort" class="sort-container">
        <el-select v-model="sortOrder" placeholder="请选择" size="small">
          <el-option label="升序" value="asc"></el-option>
          <el-option label="降序" value="desc"></el-option>
        </el-select>
        <el-input
          v-model="sortField"
          placeholder="请输入字段名"
          size="small"
          clearable
        >
        </el-input>
        <el-button
          type="primary"
          size="small"
          @click="sortTable"
        >
          <i class="el-icon-sort"></i>
        </el-button>
      </el-menu-item>
    </el-menu>

    <!-- 表选择器和搜索 -->
    <el-form :inline="true" class="demo-form-inline" style="margin-top: 20px;">
      <el-form-item label="选择数据表">
        <el-select v-model="currentTable" placeholder="请选择数据表" @change="onTableChange">
          <el-option
            v-for="table in tables"
            :key="table"
            :label="table"
            :value="table"
          ></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="搜索">
        <el-input v-model="searchQuery" placeholder="输入搜索内容" @keyup.enter.native="searchData"></el-input>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="searchData">搜索</el-button>
      </el-form-item>
    </el-form>

    <!-- 操作按钮组 -->
    <el-row :gutter="10" style="margin-top: 20px;">
      <el-button type="danger" plain @click="deleteSelected" :disabled="!selectedRows.length">
        <i class="el-icon-delete"></i> 批量删除
      </el-button>
      <el-button type="primary" plain @click="showEditDialog">
        <i class="el-icon-plus"></i> 新增记录
      </el-button>
      <el-button type="info" plain @click="showStatsDialog">
        <i class="el-icon-s-data"></i> 数据统计
      </el-button>
    </el-row>

    <!-- 编辑对话框 -->
    <el-dialog
      title="编辑记录"
      :visible.sync="editDialogVisible"
      width="60%"
      center
    >
      <el-form ref="editForm" :model="currentRecord" label-width="120px" :rules="editRules" class="dialog-form">
        <el-form-item v-for="field in tableFields" :key="field.Field" :label="field.Field" :prop="field.Field">
          <el-input v-model="currentRecord[field.Field]" placeholder="输入内容"></el-input>
        </el-form-item>
        <el-form-item style="text-align: right; margin-top: 20px;">
          <el-button @click="editDialogVisible = false">取消</el-button>
          <el-button type="primary" @click="saveRecord">提交</el-button>
        </el-form-item>
      </el-form>
    </el-dialog>

    <!-- 统计对话框 -->
    <el-dialog
      title="数据统计"
      :visible.sync="statsDialogVisible"
      width="50%"
      center
    >
      <el-form :inline="true" class="demo-form-inline">
        <el-form-item label="选择字段">
          <el-select v-model="statsField" placeholder="请选择字段">
            <el-option
              v-for="field in tableFields"
              :key="field.Field"
              :label="field.Field"
              :value="field.Field"
            ></el-option>
          </el-select>
        </el-form-item>
        <el-form-item label="统计类型">
          <el-select v-model="statsType" placeholder="请选择类型">
            <el-option label="平均值" value="avg"></el-option>
            <el-option label="中位数" value="median"></el-option>
            <el-option label="众数" value="mode"></el-option>
            <el-option label="极差" value="range"></el-option>
            <el-option label="标准差" value="stddev"></el-option>
          </el-select>
        </el-form-item>
        <el-form-item>
          <el-button type="primary" @click="calculateStats">计算</el-button>
        </el-form-item>
      </el-form>
      <div v-if="statsResult" class="stats-result">
        <div>字段：<strong>{{ statsField }}</strong></div>
        <div>统计类型：<strong v-text="getStatsTypeName(statsType)"></strong></div>
        <div>结果：<strong>{{ statsResult }}</strong></div>
      </div>
    </el-dialog>

    <!-- 数据表格 -->
    <div class="table-container" style="margin-top: 20px;">
      <el-table
        :data="tableData"
        style="width: 100%"
        @selection-change="handleSelectionChange"
        stripe
        v-loading="loading"
      >
        <el-table-column type="selection" width="55"></el-table-column>
        <el-table-column type="index" width="50"></el-table-column>

        <el-table-column
          v-for="field in tableFields"
          :key="field.Field"
          :prop="field.Field"
          :label="field.Field"
          align="center"
          :show-overflow-tooltip="true"
        >
          <template slot-scope="scope">
            <span v-if="currentTable === 'stock_data' && (field.Field === 'price_change' || field.Field === 'change_percentage')"
                  v-html="formatPriceField(scope.row, field.Field)">
            </span>
            <span v-else v-text="scope.row[field.Field] || '-'">
            </span>
          </template>
        </el-table-column>

        <el-table-column align="center" label="操作" width="120">
          <template slot-scope="scope">
            <el-button type="primary" size="mini" @click="editRecord(scope.row)">
              <i class="el-icon-edit"></i>
            </el-button>
            <el-button type="danger" size="mini" @click="deleteRecord(scope.row)">
              <i class="el-icon-delete"></i>
            </el-button>
          </template>
        </el-table-column>
      </el-table>

      <!-- 空状态 -->
      <div v-else-if="tableFields.length" class="empty-state text-center">
        <el-empty description="未找到匹配的数据"></el-empty>
      </div>
      <div v-else class="empty-state text-center">
        <el-empty description="请选择数据表"></el-empty>
      </div>
    </div>

    <!-- 分页 -->
    <div class="pagination-container" style="margin-top: 20px; text-align: right;" v-if="tableData.length">
      <el-pagination
        @size-change="handlePageSizeChange"
        @current-change="handleCurrentPageChange"
        :current-page="currentPage"
        :page-sizes="[10, 20, 50, 100]"
        :page-size="pageSize"
        layout="total, sizes, prev, pager, next, jumper"
        :total="totalCount"
      ></el-pagination>
    </div>
  </div>
</div>

<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/element-ui@2.15.14/lib/theme-chalk/index.css">
<script src="https://cdn.jsdelivr.net/npm/element-ui@2.15.14/lib/index.js"></script>
<script src="https://cdn.jsdelivr.net/npm/axios@0.21.1/dist/axios.min.js"></script>

<script>
document.addEventListener('DOMContentLoaded', function() {
  new Vue({
    el: "#app",
    data() {
      return {
        tables: [],
        currentTable: "",
        tableFields: [],
        tableData: [],
        searchQuery: "",
        currentPage: 1,
        pageSize: 10,
        totalCount: 0,
        selectedRows: [],
        editDialogVisible: false,
        currentRecord: {},
        activeIndex: '1',
        sortField: '',
        sortOrder: 'asc',
        statsDialogVisible: false,
        statsField: '',
        statsType: 'avg',
        statsResult: null,
        loading: false,
        editRules: {}
      }
    },
    computed: {
      displayData() {
        const start = (this.currentPage - 1) * this.pageSize;
        const end = start + this.pageSize;
        return this.tableData.slice(start, end);
      }
    },
    mounted() {
      this.initApp();
    },
    methods: {
      async initApp() {
        try {
          this.loading = true;
          await this.fetchTables();
        } catch (error) {
          console.error('应用初始化失败', error);
          this.$message.error('数据加载失败，请刷新页面');
        } finally {
          this.loading = false;
        }
      },

      fetchTables() {
        return axios.get('http://127.0.0.1:8080/tables')
          .then(response => {
            this.tables = response.data;
            if (this.tables.length) {
              this.currentTable = this.tables[0];
              return this.onTableChange();
            }
          })
          .catch(error => {
            console.error('获取数据表失败', error);
            this.$message.error('获取数据表失败');
            throw error;
          });
      },

      onTableChange() {
        if (!this.currentTable) return;
        this.loading = true;
        axios.get(`http://127.0.0.1:8080/${this.currentTable}/structure`)
          .then(response => {
            this.tableFields = response.data;
            this.generateEditRules();
            this.fetchData();
          })
          .catch(error => {
            console.error('获取表结构失败', error);
            this.$message.error('获取表结构失败');
          })
          .finally(() => {
            this.loading = false;
          });
      },

      generateEditRules() {
        this.editRules = {};
        this.tableFields.forEach(field => {
          if (field.Field !== 'id') {
            this.editRules[field.Field] = [{ required: true, message: `请输入${field.Field}`, trigger: 'blur' }];
          }
        });
      },

      fetchData() {
        if (!this.currentTable) return;
        this.loading = true;
        const params = {
          currentPage: this.currentPage,
          pageSize: this.pageSize,
          sortField: this.sortField,
          sortOrder: this.sortOrder
        };
        const data = this.searchQuery ? { search: this.searchQuery } : {};
        axios.post(`http://127.0.0.1:8080/${this.currentTable}/find`, data, { params })
          .then(response => {
            this.tableData = response.data.rows || [];
            this.totalCount = response.data.totalCount || 0;
          })
          .catch(error => {
            console.error('获取数据失败', error);
            this.$message.error('获取数据失败');
          })
          .finally(() => {
            this.loading = false;
          });
      },

      handleSelect(key, keyPath) {
        this.activeIndex = key;
        const routeMap = {
          '1': '/stock',
          '2': '/next',
          '3': '/shenzhen',
          '4': '/tospider',
          '5': '/process'
        };
        const route = routeMap[key];
        if (route) {
          // 防止重复点击同一菜单时刷新页面
          if (window.location.pathname !== route) {
            window.location.href = route;
          }
        }
      },

      searchData() {
        this.currentPage = 1;
        this.fetchData();
      },

      handleSelectionChange(rows) {
        this.selectedRows = rows;
      },

      showEditDialog(record = null) {
        if (record) {
          this.currentRecord = { ...record };
        } else {
          this.currentRecord = {};
        }
        this.editDialogVisible = true;
      },

      editRecord(row) {
        this.showEditDialog(row);
      },

      saveRecord() {
        this.$refs.editForm.validate(valid => {
          if (valid) {
            const isEdit = !!this.currentRecord.id;
            const method = isEdit ? 'update' : 'add';
            const url = `http://127.0.0.1:8080/${this.currentTable}/${method}`;
            const params = isEdit ? { id: this.currentRecord.id } : {};

            axios.post(url, this.currentRecord, { params })
              .then(response => {
                if (response.data.success) {
                  this.editDialogVisible = false;
                  this.fetchData();
                  this.$message.success(`${isEdit ? '更新' : '添加'}成功`);
                } else {
                  this.$message.error(response.data.message || `${isEdit ? '更新' : '添加'}失败`);
                }
              })
              .catch(error => {
                console.error(`${isEdit ? '更新' : '添加'}失败`, error);
                this.$message.error(`${isEdit ? '更新' : '添加'}失败`);
              });
          }
        });
      },

      deleteRecord(row) {
        this.$confirm('确定要删除这条记录吗？', '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          axios.delete(`http://127.0.0.1:8080/${this.currentTable}/delete`, {
            params: { id: row.id }
          })
          .then(response => {
            if (response.data.success) {
              this.fetchData();
              this.$message.success('删除成功');
            } else {
              this.$message.error(response.data.message || '删除失败');
            }
          })
          .catch(error => {
            console.error('删除失败', error);
            this.$message.error('删除失败');
          });
        }).catch(() => {});
      },

      deleteSelected() {
        if (!this.selectedRows.length) {
          this.$message.warning('请选择要删除的记录');
          return;
        }

        this.$confirm(`确定要删除选中的 ${this.selectedRows.length} 条记录吗？`, '提示', {
          confirmButtonText: '确定',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          const ids = this.selectedRows.map(row => row.id);

          axios.post(`http://127.0.0.1:8080/${this.currentTable}/delete`, ids)
            .then(response => {
              if (response.data.success) {
                this.fetchData();
                this.selectedRows = [];
                this.$message.success(`成功删除 ${ids.length} 条记录`);
              } else {
                this.$message.error(response.data.message || '删除失败');
              }
            })
            .catch(error => {
              console.error('批量删除失败', error);
              this.$message.error('批量删除失败');
            });
        }).catch(() => {});
      },

      formatPriceField(row, field) {
        const value = parseFloat(row[field]);
        if (isNaN(value)) return row[field];

        const isPercentage = field === 'change_percentage';
        const formattedValue = isPercentage ? value.toFixed(2) + '%' : value.toFixed(2);

        if (value > 0) {
          return `<span class="price-up">+${formattedValue}</span>`;
        } else if (value < 0) {
          return `<span class="price-down">${formattedValue}</span>`;
        } else {
          return formattedValue;
        }
      },

      handlePageSizeChange(size) {
        this.pageSize = size;
        this.fetchData();
      },

      handleCurrentPageChange(page) {
        this.currentPage = page;
        this.fetchData();
      },

      sortTable() {
        if (!this.sortField) {
          this.$message.warning('请输入要排序的字段');
          return;
        }

        const fieldExists = this.tableFields.some(field => field.Field === this.sortField);
        if (!fieldExists) {
          this.$message.error(`字段 "${this.sortField}" 不存在`);
          return;
        }

        this.currentPage = 1;
        this.fetchData();
        this.$message({
          message: `已按字段 "${this.sortField}" ${this.sortOrder === 'asc' ? '升序' : '降序'}排序`,
          type: 'success'
        });
      },

      showStatsDialog() {
        if (!this.tableFields.length) {
          this.$message.warning('请先选择数据表');
          return;
        }
        this.statsDialogVisible = true;
        this.statsResult = null;
        // 自动选择第一个数值字段
        const numericField = this.tableFields.find(
          f => /int|float|decimal/i.test(f.Type)
        );
        if (numericField) {
          this.statsField = numericField.Field;
        }
      },

      calculateStats() {
        if (!this.statsField || !this.statsType) {
          this.$message.warning('请选择字段和统计类型');
          return;
        }

        const values = this.tableData
          .map(row => parseFloat(row[this.statsField]))
          .filter(value => !isNaN(value));

        if (values.length === 0) {
          this.$message.error('没有有效的数值数据');
          return;
        }

        let result;

        try {
          switch (this.statsType) {
            case 'avg': // 平均值
              result = values.reduce((sum, val) => sum + val, 0) / values.length;
              break;

            case 'median': // 中位数
              const sorted = [...values].sort((a, b) => a - b);
              const mid = Math.floor(sorted.length / 2);
              result = sorted.length % 2 === 0
                ? (sorted[mid - 1] + sorted[mid]) / 2
                : sorted[mid];
              break;

            case 'mode': // 众数
              const counts = values.reduce((acc, val) => {
                acc[val] = (acc[val] || 0) + 1;
                return acc;
              }, {});
              let maxCount = 0;
              let modes = [];
              for (const [num, count] of Object.entries(counts)) {
                if (count > maxCount) {
                  maxCount = count;
                  modes = [parseFloat(num)];
                } else if (count === maxCount) {
                  modes.push(parseFloat(num));
                }
              }
              result = modes.length === 1 ? modes[0] : modes;
              break;

            case 'range': // 极差
              result = Math.max(...values) - Math.min(...values);
              break;

            case 'stddev': // 标准差
              const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
              const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length;
              result = Math.sqrt(variance);
              break;

            default:
              this.$message.error('不支持的统计类型');
              return;
          }

          // 格式化结果
          if (typeof result === 'number') {
            this.statsResult = result.toFixed(2);
          } else {
            this.statsResult = JSON.stringify(result);
          }
        } catch (error) {
          console.error('统计计算错误', error);
          this.$message.error('统计计算失败');
        }
      },

      getStatsTypeName(type) {
        const types = {
          'avg': '平均值',
          'median': '中位数',
          'mode': '众数',
          'range': '极差',
          'stddev': '标准差'
        };
        return types[type] || type;
      }
    }
  });
});
</script>

<style>
[v-cloak] { display: none; }
.dialog-form { padding: 20px 0; }
.empty-state { margin-top: 40px; }
</style>
</body>
</html>